<!DOCTYPE HTML>
<html lang="zh-Hans" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>Tokio internals - Rust 优秀博文</title>


        <!-- Custom HTML head -->
        
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="../../favicon.svg">
        <link rel="shortcut icon" href="../../favicon.png">
        <link rel="stylesheet" href="../../css/variables.css">
        <link rel="stylesheet" href="../../css/general.css">
        <link rel="stylesheet" href="../../css/chrome.css">
        <link rel="stylesheet" href="../../css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="../../FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="../../fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="../../highlight.css">
        <link rel="stylesheet" href="../../tomorrow-night.css">
        <link rel="stylesheet" href="../../ayu-highlight.css">

        <!-- Custom theme stylesheets -->

    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "../../";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">1.</strong> 类型系统</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow.html"><strong aria-hidden="true">1.1.</strong> Rust Concept Clarification Deref vs AsRef vs Borrow vs Cow</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust_Concept_Clarification_Deref_vs_AsRef_vs_Borrow_vs_Cow/Deref_AsRef_Borrow_Cow释义.html"><strong aria-hidden="true">1.2.</strong> Deref AsRef Borrow Cow 释义</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然/Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然.html"><strong aria-hidden="true">1.3.</strong> Rust的Borrow和AsRef：让你的代码用起来像呼吸一样自然</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust的Cow类型有什么用？详解Cow及其用途/Rust的Cow类型有什么用？详解Cow及其用途.html"><strong aria-hidden="true">1.4.</strong> Rust的Cow类型有什么用？详解Cow及其用途</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/判别Fn、FnMut、FnOnce的标准/判别Fn、FnMut、FnOnce的标准.html"><strong aria-hidden="true">1.5.</strong> 判别Fn、FnMut、FnOnce的标准</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/一行代码告诉你内部可变性的真相(UnsafeCell)/一行代码告诉你内部可变性的真相(UnsafeCell).html"><strong aria-hidden="true">1.6.</strong> 一行代码告诉你内部可变性的真相(UnsafeCell)</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Tour_of_Rust's_Standard_Library_Traits/Tour_of_Rust's_Standard_Library_Traits.html"><strong aria-hidden="true">1.7.</strong> Tour of Rust's Standard Library Traits</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/逆变、协变与子类型，以及Rust/逆变、协变与子类型，以及Rust.html"><strong aria-hidden="true">1.8.</strong> 逆变、协变与子类型，以及Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust自引用结构、Pin与Unpin/Rust自引用结构、Pin与Unpin.html"><strong aria-hidden="true">1.9.</strong> Rust自引用结构、Pin与Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/为什么Rust需要Pin,Unpin/为什么Rust需要Pin,Unpin.html"><strong aria-hidden="true">1.10.</strong> 译：为什么 Rust 需要 Pin, Unpin ？</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/定海神针Pin和Unpin/定海神针Pin和Unpin.html"><strong aria-hidden="true">1.11.</strong> 译：定海神针 Pin 和 Unpin</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/sizedness-in-rust/sizedness-in-rust.html"><strong aria-hidden="true">1.12.</strong> Sizedness in Rust</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/Rust生命周期集大成者PhantomData〈T〉/Rust生命周期集大成者PhantomData〈T〉.html"><strong aria-hidden="true">1.13.</strong> Rust生命周期集大成者 PhantomData&lt;T&gt;</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操_Part_0.html"><strong aria-hidden="true">1.14.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操 Part 0</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：GAT实现引用类型关联_Part_1.html"><strong aria-hidden="true">1.15.</strong> 数据库表达式执行的黑魔法：GAT实现引用类型关联 Part 1</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用HRTB写bound_Part_2.html"><strong aria-hidden="true">1.16.</strong> 数据库表达式执行的黑魔法：用HRTB写bound Part 2</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码_Part_3_&_4.html"><strong aria-hidden="true">1.17.</strong> 数据库表达式执行的黑魔法：用Rust做类型体操之用宏展开重复代码 Part 3 & 4</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化_Part_5_&_6.html"><strong aria-hidden="true">1.18.</strong> 数据库表达式执行的黑魔法：与Rust编译器斗智斗勇之表达式向量化 Part 5 & 6</a></li><li class="chapter-item expanded "><a href="../../01_类型系统/数据库表达式执行的黑魔法：用Rust做类型体操/数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型_Part_7.html"><strong aria-hidden="true">1.19.</strong> 数据库表达式执行的黑魔法：在Rust中用宏关联逻辑类型和实际类型 Part 7</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">2.</strong> 生命周期</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../02_生命周期/Rust中的生命周期——从StrSplit实例说开去/Rust中的生命周期——从StrSplit实例说开去.html"><strong aria-hidden="true">2.1.</strong> Rust中的生命周期——从StrSplit实例说开去</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/与ChatGPT深度对话来学Rust生命周期/与ChatGPT深度对话来学Rust生命周期.html"><strong aria-hidden="true">2.2.</strong> 与ChatGPT深度对话来学Rust生命周期</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（1）/进击的Rust生命周期——early_bound与late_bound（1）.html"><strong aria-hidden="true">2.3.</strong> 进击的Rust生命周期——early_bound与late_bound（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——early_bound与late_bound（2）/进击的Rust生命周期——early_bound与late_bound（2）.html"><strong aria-hidden="true">2.4.</strong> 进击的Rust生命周期——early_bound与late_bound（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（1）/进击的Rust生命周期——一力降十会的MIR（1）.html"><strong aria-hidden="true">2.5.</strong> 进击的Rust生命周期——一力降十会的MIR（1）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/进击的Rust生命周期——一力降十会的MIR（2）/进击的Rust生命周期——一力降十会的MIR（2）.html"><strong aria-hidden="true">2.6.</strong> 进击的Rust生命周期——一力降十会的MIR（2）</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Common_Rust_Lifetime_Misconceptions/Common_Rust_Lifetime_Misconceptions.html"><strong aria-hidden="true">2.7.</strong> Common Rust Lifetime Misconceptions</a></li><li class="chapter-item expanded "><a href="../../02_生命周期/Rust生命周期常见误区/Rust生命周期常见误区.html"><strong aria-hidden="true">2.8.</strong> 译：Rust生命周期常见误区</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">3.</strong> 无畏并发</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../05_无畏并发/简单写个Rust无锁队列/简单写个Rust无锁队列.html"><strong aria-hidden="true">3.1.</strong> 简单写个Rust无锁队列</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——混合自旋锁/进击的Rust多线程——混合自旋锁.html"><strong aria-hidden="true">3.2.</strong> 进击的Rust多线程——混合自旋锁</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/An_unsafe_tour_of_Rust's_Send_and_Sync/An_unsafe_tour_of_Rust's_Send_and_Sync.html"><strong aria-hidden="true">3.3.</strong> An unsafe tour of Rust's Send and Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——Send与Sync/进击的Rust多线程——Send与Sync.html"><strong aria-hidden="true">3.4.</strong> 进击的Rust多线程——Send与Sync</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/进击的Rust多线程——离经叛道的PhantomData/进击的Rust多线程——离经叛道的PhantomData.html"><strong aria-hidden="true">3.5.</strong> 进击的Rust多线程——离经叛道的PhantomData</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust_Async_Pin概念解析/Rust_Async_Pin概念解析.html"><strong aria-hidden="true">3.6.</strong> Rust Async: Pin概念解析</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust和C++的并发库对比/Rust和C++的并发库对比.html"><strong aria-hidden="true">3.7.</strong> 译：Rust 和 C++ 的并发库对比</a></li><li class="chapter-item expanded "><a href="../../05_无畏并发/Rust原子类型和内存排序/Rust原子类型和内存排序.html"><strong aria-hidden="true">3.8.</strong> Rust原子类型和内存排序</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">4.</strong> 网络编程</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../06_网络编程/从编解码层面理解WebSocket_手写一个WebSocket/从编解码层面理解WebSocket_手写一个WebSocket.html"><strong aria-hidden="true">4.1.</strong> 从编解码层面理解WebSocket 手写一 个WebSocket</a></li><li class="chapter-item expanded "><a href="../../06_网络编程/透过Rust探索系统的本原：网络篇/透过Rust探索系统的本原：网络篇.html"><strong aria-hidden="true">4.2.</strong> 透过Rust探索系统的本原：网络篇</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">5.</strong> 轮子系列</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../07_轮子系列/700行Rust写一个内存分配器/700行Rust写一个内存分配器.html"><strong aria-hidden="true">5.1.</strong> 700行Rust写一个内存分配器</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust：网络库的实现思路/Rust：网络库的实现思路.html"><strong aria-hidden="true">5.2.</strong> Rust：网络库的实现思路</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/Rust异步运行时基础部件/Rust异步运行时基础部件.html"><strong aria-hidden="true">5.3.</strong> Rust异步运行时基础部件</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（1）.html"><strong aria-hidden="true">5.4.</strong> 使用Rust+epoll编写异步IO框架（1）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（2）.html"><strong aria-hidden="true">5.5.</strong> 使用Rust+epoll编写异步IO框架（2）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/使用Rust+epoll编写异步IO框架/使用Rust+epoll编写异步IO框架（3）.html"><strong aria-hidden="true">5.6.</strong> 使用Rust+epoll编写异步IO框架（3）</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day1.html"><strong aria-hidden="true">5.7.</strong> 用rust从零开发一套web框架：day1</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day2.html"><strong aria-hidden="true">5.8.</strong> 用rust从零开发一套web框架：day2</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day3.html"><strong aria-hidden="true">5.9.</strong> 用rust从零开发一套web框架：day3</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day4.html"><strong aria-hidden="true">5.10.</strong> 用rust从零开发一套web框架：day4</a></li><li class="chapter-item expanded "><a href="../../07_轮子系列/用rust从零开发一套web框架/用rust从零开发一套web框架：day5.html"><strong aria-hidden="true">5.11.</strong> 用rust从零开发一套web框架：day5</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">6.</strong> 奇技淫巧</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Copy-On-Write是不是优化？/Copy-On-Write是不是优化？.html"><strong aria-hidden="true">6.1.</strong> 译：Copy-On-Write是不是优化？</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/揭秘神奇的Rust_Axum风格的函数实现/揭秘神奇的Rust_Axum风格的函数实现.html"><strong aria-hidden="true">6.2.</strong> 译：揭秘神奇的 Rust Axum 风格的函数实现</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/“变长参数”函数与回调/“变长参数”函数与回调.html"><strong aria-hidden="true">6.3.</strong> “变长参数”函数与回调</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Rust字符串格式化的幕后：format_args!()/Rust字符串格式化的幕后：format_args!().html"><strong aria-hidden="true">6.4.</strong> 译：Rust字符串格式化的幕后：format_args!()</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/给Rust带来一点C++特产/给Rust带来一点C++特产.html"><strong aria-hidden="true">6.5.</strong> 给Rust带来一点C++特产</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/一步步实现_Rust_Bevy_ECS_的_System_简化版本/一步步实现_Rust_Bevy_ECS_的_System_简化版本.html"><strong aria-hidden="true">6.6.</strong> 一步步实现 Rust Bevy ECS 的 System 简化版本</a></li><li class="chapter-item expanded "><a href="../../08_奇技淫巧/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples/Exploring_Design_Patterns_in_Rust_with_Algorithmic_Trading_Examples.html"><strong aria-hidden="true">6.7.</strong> Exploring Design Patterns in Rust with Algorithmic Trading Examples</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">7.</strong> 源码分析</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：bytes源码分析/Rust并发：bytes源码分析.html"><strong aria-hidden="true">7.1.</strong> Rust并发：bytes源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库Arc源码分析/Rust并发：标准库Arc源码分析.html"><strong aria-hidden="true">7.2.</strong> Rust并发：标准库Arc源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust并发：标准库sync_Once源码分析/Rust并发：标准库sync_Once源码分析.html"><strong aria-hidden="true">7.3.</strong> Rust并发：标准库sync::Once源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：引用计数Rc/Rust源码阅读：引用计数Rc.html"><strong aria-hidden="true">7.4.</strong> Rust源码阅读：引用计数Rc</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust源码阅读：Cell、RefCell与内部可变性/Rust源码阅读：Cell、RefCell与内部可变性.html"><strong aria-hidden="true">7.5.</strong> Rust源码阅读： Cell、RefCell与内部可变性</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/关于_Rust_的_UnsafeCell、Cell_与_RefCell/关于_Rust_的_UnsafeCell、Cell_与_RefCell.html"><strong aria-hidden="true">7.6.</strong> 关于 Rust 的 UnsafeCell、Cell 与 RefCell</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Async_async-stream源码分析/Rust_Async_async-stream源码分析.html"><strong aria-hidden="true">7.7.</strong> Rust Async: async-stream源码分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/走进Tokio的异步世界/走进Tokio的异步世界.html"><strong aria-hidden="true">7.8.</strong> 走进 Tokio 的异步世界</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html"><strong aria-hidden="true">7.9.</strong> tokio.rs runtime 的实现</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/Tokio_internals.html" class="active"><strong aria-hidden="true">7.10.</strong> Tokio internals</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_internals/译文：Tokio內部机制.html"><strong aria-hidden="true">7.11.</strong> 译：Tokio 内部机制</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Rust_Axum_HTTP_框架的架构分析/Rust_Axum_HTTP_框架的架构分析.html"><strong aria-hidden="true">7.12.</strong> Rust Axum HTTP 框架的架构分析</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/安利一个Rust_Game_Engine：Bevy--ECS部分/安利一个Rust_Game_Engine：Bevy--ECS部分.html"><strong aria-hidden="true">7.13.</strong> 安利一个Rust Game Engine：Bevy--ECS部分</a></li><li class="chapter-item expanded "><a href="../../09_源码分析/Tokio_解析之任务调度/Tokio_解析之任务调度.html"><strong aria-hidden="true">7.14.</strong> Tokio 解析之任务调度</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">8.</strong> 生态观察</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../11_生态观察/Rust_web_frameworks_have_subpar_error_reporting/Rust_web_frameworks_have_subpar_error_reporting.html"><strong aria-hidden="true">8.1.</strong> Rust web frameworks have subpar error reporting</a></li><li class="chapter-item expanded "><a href="../../11_生态观察/SeaORM：要做Rust版本的ActiveRecord/SeaORM：要做Rust版本的ActiveRecord.html"><strong aria-hidden="true">8.2.</strong> SeaORM：要做Rust版本的ActiveRecord</a></li></ol></li><li class="chapter-item expanded "><a href="../../empty.html"><strong aria-hidden="true">9.</strong> 死灵终极</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_总述.html"><strong aria-hidden="true">9.1.</strong> 译：Learn Rust the Dangerous Way 总述</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_0.html"><strong aria-hidden="true">9.2.</strong> 译：Learn Rust the Dangerous Way 0</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_1.html"><strong aria-hidden="true">9.3.</strong> 译：Learn Rust the Dangerous Way 1</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_2.html"><strong aria-hidden="true">9.4.</strong> 译：Learn Rust the Dangerous Way 2</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_3.html"><strong aria-hidden="true">9.5.</strong> 译：Learn Rust the Dangerous Way 3</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_4.html"><strong aria-hidden="true">9.6.</strong> 译：Learn Rust the Dangerous Way 4</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Learn_Rust_the_Dangerous_Way_系列文章翻译/Learn_Rust_the_Dangerous_Way_系列文章翻译_5.html"><strong aria-hidden="true">9.7.</strong> 译：Learn Rust the Dangerous Way 5</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（一）.html"><strong aria-hidden="true">9.8.</strong> Unsafe Rust 随堂小测（一）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（二）.html"><strong aria-hidden="true">9.9.</strong> Unsafe Rust 随堂小测（二）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测（三）.html"><strong aria-hidden="true">9.10.</strong> Unsafe Rust 随堂小测（三）</a></li><li class="chapter-item expanded "><a href="../../12_死灵终极/Unsafe_Rust_随堂小测/Unsafe_Rust_随堂小测参考答案.html"><strong aria-hidden="true">9.11.</strong> Unsafe Rust 随堂小测参考答案</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">Rust 优秀博文</h1>

                    <div class="right-buttons">
                        <a href="../../print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="tokio-internals-understanding-rusts-asynchronous-io-framework-from-the-bottom-up"><a class="header" href="#tokio-internals-understanding-rusts-asynchronous-io-framework-from-the-bottom-up">Tokio internals: Understanding Rust's asynchronous I/O framework from the bottom up</a></h1>
<p>December 18, 2017</p>
<p>原文：<a href="https://cafbit.com/post/tokio_internals">https://cafbit.com/post/tokio_internals</a></p>
<p>作者：David Simmons</p>
<p><a href="https://tokio.rs/">Tokio</a> is a Rust framework for developing applications which perform asynchronous I/O — an event-driven approach that can often achieve better scalability, performance, and resource usage than conventional synchronous I/O. Unfortunately, Tokio is notoriously difficult to learn due to its sophisticated abstractions. Even after reading the tutorials, I didn't feel that I had internalized the abstractions sufficiently to be able to reason about what was actually happening.</p>
<p>My prior experience with asynchronous I/O programming may have even hindered my Tokio education. I'm accustomed to using the operating system's selection facility (e.g. Linux epoll) as a starting point, and then moving on to dispatch, state machines, and so forth. Starting with the Tokio abstractions with no clear insight into where and how the underlying <code>epoll_wait()</code> happens, I found it difficult to connect all the dots. Tokio and its future-driven approach felt like something of a black box.</p>
<p>Instead of continuing on a top-down approach to learning Tokio, I decided to instead take a bottom-up approach by studying the source code to understand exactly how the current concrete implementation drives the progression from epoll events to I/O consumption within a <code>Future::poll()</code>. I won't go into great detail about the high-level usage of Tokio and futures, as that is better covered in the <a href="https://tokio.rs/docs/getting-started/tokio/">existing tutorials</a>. I'm also not going to discuss the general problem of asynchronous I/O beyond a short summary, since entire books could be written on the subject. My goal is simply to have some confidence that futures and Tokio's polling work the way I expect.</p>
<p>First, some important disclaimers. Note that Tokio is actively being developed, so some of the observations here may quickly become out-of-date. For the purposes of this study, I used <code>tokio-core 0.1.10</code>, <code>futures 0.1.17</code>, and <code>mio 0.6.10</code>. Since I wanted to understand Tokio at its lowest levels, I did not consider higher-level crates like <code>tokio-proto</code> and <code>tokio-service</code>. The tokio-core event system itself has a lot of moving pieces, most of which I avoid discussing in the interest of brevity. I studied Tokio on a Linux system, and some of the discussion necessarily touches on platform-dependent implementation details such as epoll. Finally, everything mentioned here is my interpretation as a newcomer to Tokio, so there could be errors or misunderstandings.</p>
<h2 id="asynchronous-io-in-a-nutshell"><a class="header" href="#asynchronous-io-in-a-nutshell">Asynchronous I/O in a nutshell</a></h2>
<p>Synchronous I/O programming involves performing I/O operations which block until completion. Reads will block until data arrives, and writes will block until the outgoing bytes can be delivered to the kernel. This fits nicely with conventional imperative programming, where a series of steps are executed one after the other. For example, consider an HTTP server that spawns a new thread for each connection. On this thread, it may read bytes until an entire request is received (blocking as needed until all bytes arrive), processes the request, and then write the response (blocking as needed until all bytes are written). This is a very straightforward approach. The downside is that a distinct thread is needed for each connection due to the blocking, each with its own stack. In many cases this is fine, and synchronous I/O is the correct approach. However, the thread overhead hinders scalability on servers trying to handle a very large number of connections (see: <a href="https://en.wikipedia.org/wiki/C10k_problem">the C10k problem</a>), and may also be excessive on low-resource systems handling a few connections.</p>
<p>If our HTTP server was written to use asynchronous I/O, on the other hand, it might perform all I/O processing on a single thread. All active connections and the listening socket would be configured as non-blocking, monitored for read/write readiness in an event loop, and execution would be dispatched to handlers as events occur. State and buffers would need to be maintained for each connection. If a handler is only able to read 100 bytes of a 200-byte request, it cannot wait for the remaining bytes to arrive, since doing so would prevent other connections from making progress. It must instead store the partial read in a buffer, keep the state set to &quot;reading request&quot;, and return to the event loop. The next time the handler is called for this connection, it may read the remainder of the request and transition to a &quot;writing response&quot; state. Implementing such a system can become hairy very fast, with complex state machines and error-prone resource management.</p>
<p>The ideal asynchronous I/O framework would provide a means of writing such I/O processing steps one after the other, as if they were blocking, but behind the scenes generate an event loop and state machines. That's a tough goal in most languages, but Tokio brings us pretty close.</p>
<h2 id="the-tokio-stack"><a class="header" href="#the-tokio-stack">The Tokio stack</a></h2>
<p><img src="assets/010.svg" alt="" /></p>
<p>The Tokio stack consists of the following components:</p>
<ol>
<li><strong>The system selector.</strong> Each operating system provides a facility for receiving I/O events, such as epoll (Linux), <code>kqueue()</code> (FreeBSD/Mac OS), or IOCP (Windows).</li>
<li><strong>Mio - Metal I/O.</strong> <a href="https://docs.rs/mio/0.6.10/mio/">Mio</a> is a Rust crate that provides a common API for low-level I/O by internally handling the specific details for each operating system. Mio deals with the specifics of each operating system's selector so you don't have to.</li>
<li><strong>Futures.</strong> <a href="https://docs.rs/futures/0.1.17/futures/">Futures</a> provide a powerful abstraction for representing things that have yet to happen. These representations can be combined in useful ways to create composite futures describing a complex sequence of events. This abstraction is general enough to be used for many things besides I/O, but in Tokio we develop our asynchronous I/O state machines as futures.</li>
<li><strong>Tokio</strong> The <code>tokio-core</code> crate provides the central event loop which integrates with Mio to respond to I/O events, and drives futures to completion.</li>
<li><strong>Your program.</strong> A program using the Tokio framework can construct asynchronous I/O systems as futures, and provide them to the Tokio event loop for execution.</li>
</ol>
<h2 id="mio-metal-io"><a class="header" href="#mio-metal-io">Mio: Metal I/O</a></h2>
<p>Mio provides a low-level I/O API allowing callers to receive events such as socket read/write readiness changes. The highlights are:</p>
<ol>
<li><strong>Poll and Evented.</strong> Mio supplies the <code>Evented</code> trait to represent anything that can be a source of events. In your event loop, you register a number of <code>Evented</code>'s with a <code>mio::Poll</code> object, then call <code>mio::Poll::poll()</code> to block until events have occurred on one or more <code>Evented</code> objects (or the specified timeout has elapsed).</li>
<li><strong>System selector.</strong> Mio provides cross-platform access to the system selector, so that Linux epoll, Windows IOCP, FreeBSD/Mac OS <code>kqueue()</code>, and potentially others can all be used with the same API. The overhead required to adapt the system selector to the Mio API varies. Because Mio provides a readiness-based API similar to Linux epoll, many parts of the API can be one-to-one mappings when using Mio on Linux. (For example, <code>mio::Events</code> essentially <em>is</em> an array of <code>struct epoll_event</code>.) In contrast, because Windows IOCP is completion-based instead of readiness-based, a bit more adaptation is required to bridge the two paradigms. Mio supplies its own versions of <code>std::net</code> structs such as <code>TcpListener</code>, <code>TcpStream</code>, and <code>UdpSocket</code>. These wrap the <code>std::net</code> versions, but default to non-blocking and provide <code>Evented</code> implementations which add the socket to the system selector.</li>
<li><strong>Non-system events.</strong> In addition to providing readiness of I/O sources, Mio can also indicate readiness events generated in user-space. For example, if a worker thread finishes a unit of work, it can signal completion to the event loop thread. Your program calls <code>Registration::new2()</code> to obtain a <code>(Registration, SetReadiness)</code> pair. The <code>Registration</code> object is an <code>Evented</code> which can be registered with Mio in your event loop, and <code>set_readiness()</code> can be called on the <code>SetReadiness</code> object whenever readiness needs to be indicated. On Linux, non-system event notifications are implemented using a pipe. When <code>SetReadiness::set_readiness()</code> is called, a <code>0x01</code> byte is written to the pipe. <code>mio::Poll</code>'s underlying epoll is configured to monitor the reading end of the pipe, so <code>epoll_wait()</code> will unblock and Mio can deliver the event to the caller. Exactly one pipe is created when <code>Poll</code> is instantiated, regardless of how many (if any) non-system events are later registered.</li>
</ol>
<p>Every <code>Evented</code> registration is associated with a caller-provided <code>usize</code> value typed as <code>mio::Token</code>, and this value is returned with events to indicate the corresponding registration. This maps nicely to the system selector in the Linux case, since the token can be placed in the 64-bit <code>epoll_data</code> union which functions in the same way.</p>
<p>To provide a concrete example of Mio operation, here's what happens internally when we use Mio to monitor a UDP socket on a Linux system:</p>
<ol>
<li>Create the socket.</li>
</ol>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let socket = mio::net::UdpSocket::bind(
    &amp;SocketAddr::new(
        std::net::IpAddr::V4(std::net::Ipv4Addr::new(127,0,0,1)),
        2000
    )
).unwrap();
<span class="boring">}
</span></code></pre></pre>
<p>This creates a Linux UDP socket, wrapped in a <code>std::net::UdpSocket</code>, which itself is wrapped in a <code>mio::net::UdpSocket</code>. The socket is set to be non-blocking.</p>
<ol start="2">
<li>Create the poll.</li>
</ol>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>let poll = mio::Poll::new().unwrap(); 
<span class="boring">}
</span></code></pre></pre>
<p>Mio initializes the system selector, readiness queue (for non-system events), and concurrency protection. The readiness queue initialization creates a pipe so readiness can be signaled from user-space, and the pipe's read file descriptor is added to the epoll. When a <code>Poll</code> object is created, it is assigned a unique <code>selector_id</code> from an incrementing counter.</p>
<ol start="3">
<li>Register the socket with the poll.</li>
</ol>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>poll.register(
    &amp;socket,
    mio::Token(0),
    mio::Ready::readable(),
    mio::PollOpt::level()
).unwrap();
<span class="boring">}
</span></code></pre></pre>
<p>The <code>UdpSocket</code>'s <code>Evented.register()</code> function is called, which proxies to a contained <code>EventedFd</code> which adds the socket's file descriptor to the poll selector (by ultimately using <code>epoll_ctl(fepd, EPOLL_CTL_ADD, fd, &amp;epoll_event)</code> where <code>epoll_event.data</code> is set to the provided token value). When a <code>UdpSocket</code> is registered, its <code>selector_id</code> is set to the <code>Poll</code>'s, thus associating it with the selector.</p>
<ol start="4">
<li>Call poll() in an event loop.</li>
</ol>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>loop {
    poll.poll(&amp;mut events, None).unwrap();
    for event in &amp;events {
        handle_event(event);
    }
}
<span class="boring">}
</span></code></pre></pre>
<p>The system selector (<code>epoll_wait()</code>) and then the readiness queue are polled for new events. (The <code>epoll_wait()</code> blocks, but because non-system events trigger epoll via the pipe in addition to pushing to the readiness queue, they will still be processed in a timely manner.) The combined set of events are made available to the caller for processing.</p>
<h2 id="futures-and-tasks"><a class="header" href="#futures-and-tasks">Futures and Tasks</a></h2>
<p><a href="https://en.wikipedia.org/wiki/Futures_and_promises">Futures</a> are techniques borrowed from functional programming whereby computation that has yet to happen can be represented as a &quot;future&quot;, and these individual futures can be combined to develop complex systems. This is useful for asynchronous I/O because the basic steps needed to perform transactions can be modeled as such combined futures. In the HTTP server example, one future may read a request by reading bytes as they become available until the end of the request is reached, at which time a &quot;Request&quot; object is yielded. Another future may process a request and yield a response, and yet another future may write responses.</p>
<p>In Rust, futures are implemented in the <a href="https://docs.rs/futures/0.1.17/futures/">futures crate</a>. You can define a future by implementing the <code>Future</code> trait, which requires a <code>poll()</code> method which is called as needed to allow the future to make progress. This method returns either an error, an indication that the future is still pending thus <code>poll()</code> should be called again later, or a yielded value if the future has reached completion. The <code>Future</code> trait also provides a great many combinators as default methods.</p>
<p>To understand futures, it is crucial to understand tasks, executors, and notifications — and how they arrange for a future's <code>poll()</code> method to be called at the right time. Every future is executed within a <code>task</code> context. A task itself is directly associated with exactly one future, but this future may be a composite future that drives many contained futures. (For example, multiple futures joined into a single future using the <code>join_all()</code> combinator, or two futures executed in series using the <code>and_then()</code> combinator.)</p>
<p>Tasks and their futures require an <em>executor</em> to run. An executor is responsible for polling the task/future at the correct times — usually when it has been notified that progress can be made. Such a notification happens when some other code calls the <code>notify()</code> method of the provided object implementing the <code>futures::executor::Notify</code> trait. An example of this can be seen in the extremely simple executor provided by the <code>futures</code> crate that is invoked when calling the <code>wait()</code> method on a future. From <a href="https://github.com/alexcrichton/futures-rs/blob/0.1.17/src/task_impl/std/mod.rs#L233">the source code</a>:</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>/// Waits for the internal future to complete, blocking this thread's
/// execution until it does.
///
/// This function will call `poll_future` in a loop, waiting for the future
/// to complete. When a future cannot make progress it will use
/// `thread::park` to block the current thread.
pub fn wait_future(&amp;mut self) -&gt; Result&lt;F::Item, F::Error&gt; {
    ThreadNotify::with_current(|notify| {

        loop {
            match self.poll_future_notify(notify, 0)? {
                Async::NotReady =&gt; notify.park(),
                Async::Ready(e) =&gt; return Ok(e),
            }
        }
    })
}
<span class="boring">}
</span></code></pre></pre>
<p>Given a <code>futures::executor::Spawn</code> object previously created to fuse a task and future, this executor calls <code>poll_future_notify()</code> in a loop. The provided <code>Notify</code> object becomes part of the task context and the future is polled. If a future's <code>poll()</code> returns <code>Async::NotReady</code> indicating that the future is still pending, it <em>must</em> arrange to be polled again in the future. It can obtain a handle to its task via <code>futures::task::current()</code> and call the <code>notify()</code> method whenever the future can again make progress. (Whenever a future is being polled, information about its associated task is stored in a thread-local which can be accessed via <code>current()</code>.) In the above case, if the poll returns <code>Async::NotReady</code>, the executor will block until the notification is received. Perhaps the future starts some work on another thread which will call <code>notify()</code> upon completion, or perhaps the <code>poll()</code> itself calls <code>notify()</code> directly before returning <code>Async::NotReady</code>. (The latter is not common, since theoretically a <code>poll()</code> should continue making progress, if possible, before returning.)</p>
<p>The Tokio event loop acts as a much more sophisticated executor that integrates with Mio events to drive futures to completion. In this case, a Mio event indicating socket readiness will result in a notification that causes the corresponding future to be polled.</p>
<p>Tasks are the basic unit of execution when dealing with futures, and are essentially <a href="https://en.wikipedia.org/wiki/Green_threads">green threads</a> providing a sort of <a href="https://en.wikipedia.org/wiki/Cooperative_multitasking">cooperative multitasking</a>, allowing multiple execution contexts on one operating system thread. When one task is unable to make progress, it will yield the processor to other runnable tasks. It is important to understand that notifications happen at the task level and not the future level. When a task is notified, it will poll its top-level future, which may result in any or all of the child futures (if present) being polled. For example, if a task's top-level future is a <code>join_all()</code> of ten other futures, and one of these futures arranges for the task to be notified, all ten futures will be polled whether they need it or not.</p>
<h2 id="tokios-interface-with-mio"><a class="header" href="#tokios-interface-with-mio">Tokio's interface with Mio</a></h2>
<p>Tokio converts task notifications into Mio events by using Mio's &quot;non-system events&quot; feature described above. After obtaining a Mio <code>(Registration, SetReadiness)</code> pair for the task, it registers the <code>Registration</code> (which is an <code>Evented</code>) with Mio's poll, then wraps the <code>SetReadiness</code> object in a <code>MySetReadiness</code> which implements the <code>Notify</code> trait. From <a href="https://github.com/tokio-rs/tokio-core/blob/0.1.10/src/reactor/mod.rs#L791">the source code</a>:</p>
<pre><code>struct MySetReadiness(mio::SetReadiness);

impl Notify for MySetReadiness {
    fn notify(&amp;self, _id: usize) {
        self.0.set_readiness(mio::Ready::readable())
              .expect(&quot;failed to set readiness&quot;);
    }
}
</code></pre>
<p>In this way, task notifications are converted into Mio events, and can be processed in Tokio's event handling and dispatch code along with other types of Mio events.</p>
<p>Just as Mio wraps <code>std::net</code> structs such as <code>UdpSocket</code>, <code>TcpListener</code>, and <code>TcpStream</code> to customize functionality, Tokio also uses composition and decoration to provide Tokio-aware versions of these types. For example, Tokio's <code>UdpSocket</code> looks something like this:</p>
<p><img src="assets/020.svg" alt="" /></p>
<p>Tokio's versions of these I/O source types provide constructors that require a handle to the event loop (<code>tokio_core::reactor::Handle</code>). When instantiated, these types will register their sockets with the event loop's Mio poll to receive edge-triggered events with a newly assigned even-numbered token. (More on this, below.) Conveniently, these types will also arrange for the current task to be notified of read/write readiness whenever the underlying I/O operation returns <code>WouldBlock</code>.</p>
<p>Tokio registers several types of <code>Evented</code>'s with Mio, keyed to specific tokens:</p>
<ul>
<li>
<p>Token 0 (<code>TOKEN_MESSAGES</code>) is used for Tokio's internal message queue, which provides a means of removing I/O sources, scheduling tasks to receive read/write readiness notifications, configuring timeouts, and running arbitrary closures in the context of the event loop. This can be used to safely communicate with the event loop from other threads. For example, <code>Remote::spawn()</code> marshals the future to the event loop via the message system.</p>
<p>The message queue is implemented as a <code>futures::sync::mpsc</code> stream. As a <code>futures::stream::Stream</code> (which is similar to a future, except it yields a sequence of values instead of a single value), the processing of this message queue is performed using the <code>MySetReadiness</code> scheme mentioned above, where the <code>Registration</code> is registered with the <code>TOKEN_MESSAGES</code> token. When <code>TOKEN_MESSAGES</code> events are received, they are dispatched to the <code>consume_queue()</code> method for processing. (Source: <code>enum Message</code>, <code>consume_queue()</code>)</p>
</li>
<li>
<p>Token 1 (<code>TOKEN_FUTURE</code>) is used to notify Tokio that the main task needs to be polled. This happens when a notification occurs which is associated with the main task. (In other words, the future passed to <code>Core::run()</code> or a child thereof, not a future running in a different task via <code>spawn()</code>.) This also uses a <code>MySetReadiness</code> scheme to translate future notifications into Mio events. Before a future running in the main task returns <code>Async::NotReady</code>, it will arrange for a notification to be sent later in a manner of its choosing. When the resulting <code>TOKEN_FUTURE</code> event is received, the Tokio event loop will re-poll the main task.</p>
</li>
<li>
<p>Even-numbered tokens greater than 1 (<code>TOKEN_START+key*2</code>) are used to indicate readiness changes on I/O sources. The key is the <code>Slab</code> key for the associated <code>Core::inner::io_dispatch Slab&lt;ScheduledIo&gt;</code> element. The Mio I/O source types (<code>UdpSocket</code>, <code>TcpListener</code>, and <code>TcpStream</code>) are registered with such a token automatically when the corresponding Tokio I/O source types are instantiated.</p>
</li>
<li>
<p>Odd-numbered tokens greater than 1 (<code>TOKEN_START+key*2+1</code>) are used to indicate that a spawned task (and thus its associated future) should be polled. The key is the <code>Slab</code> key for the associated <code>Core::inner::task_dispatch Slab&lt;ScheduledTask&gt;</code> element. As with <code>TOKEN_MESSAGES</code> and <code>TOKEN_FUTURE</code> events, these also use the <code>MySetReadiness</code> plumbing.</p>
</li>
</ul>
<h2 id="tokio-event-loop"><a class="header" href="#tokio-event-loop">Tokio event loop</a></h2>
<p>Tokio, specifically <code>tokio_core::reactor::Core</code>, provides the event loop to manage futures and tasks, drive futures to completion, and interface with Mio so that I/O events will result in the correct tasks being notified. Using the event loop involves instantiating the <code>Core</code> with <code>Core::new()</code> and calling <code>Core::run()</code> with a single future. The event loop will drive the provided future to completion before returning. For server applications, this future is likely to be long-lived. It may, for example, use a <code>TcpListener</code> to continuously accept new incoming connections, each of which may be handled by their own future running independently in a separate task created by <code>Handle.spawn()</code>.</p>
<p>The following flow chart outlines the basic steps of the Tokio event loop:</p>
<p><img src="assets/030.svg" alt="" /></p>
<h2 id="what-happens-when-data-arrives-on-a-socket"><a class="header" href="#what-happens-when-data-arrives-on-a-socket">What happens when data arrives on a socket?</a></h2>
<p>A useful exercise for understanding Tokio is to examine the steps that occur within the event loop when data arrives on a socket. I was surprised to discover that this ends up being a two-part process, with each part requiring a separate epoll transaction in a separate iteration of the event loop. The first part responds to a socket becoming read-ready (i.e., a Mio event with an even-numbered token greater than one for spawned tasks, or <code>TOKEN_FUTURE</code> for the main task) by sending a notification to the task which is interested in the socket. The second part handles the notification (i.e., a Mio event with an odd-numbered token greater than one) by polling the task and its associated future. We'll consider the steps in a scenario where a spawned future is reading from a <code>UdpSocket</code> on a Linux system, from the top of the Tokio event loop, assuming that a previous poll of the future resulted in a <code>recv_from()</code> returning a <code>WouldBlock</code> error.</p>
<p><img src="assets/040.svg" alt="" /></p>
<p>The Tokio event loop calls <code>mio::Poll::poll()</code>, which in turn (on Linux) calls <code>epoll_wait()</code>, which blocks until some readiness change event occurs on one of the monitored file descriptors. When this happens, <code>epoll_wait()</code> returns an array of <code>epoll_event</code> structs describing what has occurred, which are translated by Mio into <code>mio::Events</code> and returned to Tokio. (On Linux, this translation should be zero-cost, since <code>mio::Events</code> is just a single-tuple struct of a <code>epoll_event</code> array.) In our case, assume the only event in the array is indicating read readiness on the socket. Because the event token is even and greater than one, Tokio interprets this as an I/O event, and looks up the details in the corresponding element of <code>Slab&lt;ScheduledIo&gt;</code>, which contains information on any tasks interested in read and write readiness for this socket. Tokio then notifies the reader task which, by way of the <code>MySetReadiness</code> glue described earlier, calls Mio's <code>set_readiness()</code>. Mio handles this non-system event by adding the event details to its readiness queue, and writing a single <code>0x01</code> byte to the readiness pipe.</p>
<p><img src="assets/050.svg" alt="" /></p>
<p>After the Tokio event loop moves to the next iteration, it once again polls Mio, which calls <code>epoll_wait()</code>, which this time returns a read readiness event occurring on Mio's readiness pipe. Mio reads the <code>0x01</code> which was previously written to the pipe, dequeues the non-system event details from the readiness queue, and returns the event to Tokio. Because the event token is odd and greater than one, Tokio interprets this as a task notification event, and looks up the details in the corresponding element of <code>Slab&lt;ScheduledTask&gt;</code>, which contains the task's original <code>Spawn</code> object returned from <code>spawn()</code>. Tokio polls the task and its future via <code>poll_future_notify()</code>. The future may then read data from the socket until it gets a <code>WouldBlock</code> error.</p>
<p>This two-iteration approach involving a pipe write and read may add a little overhead when compared to other asynchronous I/O event loops. In a single-threaded program, it is weird to look at the <code>strace</code> and see a thread use a pipe to communicate with itself:</p>
<pre><code>pipe2([4, 5], O_NONBLOCK|O_CLOEXEC) = 0
...
epoll_wait(3, [{EPOLLIN|EPOLLOUT, {u32=14, u64=14}}], 1024, -1) = 1
write(5, &quot;\1&quot;, 1) = 1
epoll_wait(3, [{EPOLLIN, {u32=4294967295, u64=18446744073709551615}}], 1024, 0) = 1
read(4, &quot;\1&quot;, 128) = 1
read(4, 0x7ffce1140f58, 128) = -1 EAGAIN (Resource temporarily unavailable)
recvfrom(12, &quot;hello\n&quot;, 1024, 0, {sa_family=AF_INET, sin_port=htons(43106), sin_addr=inet_addr(&quot;127.0.0.1&quot;)}, [16]) = 6
recvfrom(12, 0x7f576621c800, 1024, 0, 0x7ffce1140070, 0x7ffce114011c) = -1 EAGAIN (Resource temporarily unavailable)
epoll_wait(3, [], 1024, 0) = 0
epoll_wait(3, 0x7f5765b24000, 1024, -1) = -1 EINTR (Interrupted system call)
</code></pre>
<p>Mio uses this pipe scheme to support the general case where <code>set_readiness()</code> may be called from other threads, and perhaps it also has some benefits in forcing the fair scheduling of events and maintaining a layer of indirection between futures and I/O.</p>
<h2 id="lessons-learned-combining-futures-vs-spawning-futures"><a class="header" href="#lessons-learned-combining-futures-vs-spawning-futures">Lessons learned: Combining futures vs. spawning futures</a></h2>
<p>When I first started exploring Tokio, I wrote a small program to listen for incoming data on several different UDP sockets. I created ten instances of a socket-reading future, each of them listening on a different port number. I naively joined them all into a single future with <code>join_all()</code>, passed the combined future to <code>Core::run()</code>, and was surprised to discover that every future was being polled whenever a single packet arrived. Also somewhat surprising was that <code>tokio_core::net::UdpSocket::recv_from()</code> (and its underlying <code>PollEvented</code>) was smart enough to avoid actually calling the operating system's <code>recvfrom()</code> on sockets that had not been flagged as read-ready in a prior Mio poll. The <code>strace</code>, reflecting a debug <code>println!()</code> in my future's <code>poll()</code>, looked something like this:</p>
<pre><code>epoll_wait(3, [{EPOLLIN|EPOLLOUT, {u32=14, u64=14}}], 1024, -1) = 1
write(5, &quot;\1&quot;, 1) = 1
epoll_wait(3, [{EPOLLIN, {u32=4294967295, u64=18446744073709551615}}], 1024, 0) = 1
read(4, &quot;\1&quot;, 128) = 1
read(4, 0x7ffc183129d8, 128) = -1 EAGAIN (Resource temporarily unavailable)
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
recvfrom(12, &quot;hello\n&quot;, 1024, 0, {sa_family=AF_INET, sin_port=htons(43106), sin_addr=inet_addr(&quot;127.0.0.1&quot;)}, [16]) = 6
getsockname(12, {sa_family=AF_INET, sin_port=htons(2006), sin_addr=inet_addr(&quot;127.0.0.1&quot;)}, [16]) = 0
write(1, &quot;recv 6 bytes from 127.0.0.1:43106 at 127.0.0.1:2006\n&quot;, 52) = 52
recvfrom(12, 0x7f2a11c1c400, 1024, 0, 0x7ffc18312ba0, 0x7ffc18312c4c) = -1 EAGAIN (Resource temporarily unavailable)
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
write(1, &quot;UdpServer::poll()...\n&quot;, 21) = 21
epoll_wait(3, [], 1024, 0) = 0
epoll_wait(3, 0x7f2a11c36000, 1024, -1) = ...
</code></pre>
<p>Since the concrete internal workings of Tokio and futures were somewhat opaque to me, I suppose I hoped there was some magic routing happening behind the scenes that would only poll the required futures. Of course, armed with a better understanding of Tokio, it's obvious that my program was using futures like this:</p>
<p><img src="assets/060.svg" alt="" /></p>
<p>This actually works fine, but is not optimal — especially if you have a lot of sockets. Because notifications happen at the task level, any notification arranged in any of the green boxes above will cause the main task to be notified. It will poll its <code>FromAll</code> future, which itself will poll each of its children. What I really need is a simple main future that uses <code>Handle::spawn()</code> to launch each of the other futures in their own tasks, resulting in an arrangement like this:</p>
<p><img src="assets/070.svg" alt="" /></p>
<p>When any future arranges a notification, it will cause only the future's specific task to be notified, and only that future will be polled. (Recall that &quot;arranging a notification&quot; happens automatically when <code>tokio_core::net::UdpSocket::recv_from()</code> receives <code>WouldBlock</code> from its underlying <code>mio::net::UdpSocket::recv_from()</code> call.) Future combinators are powerful tools for describing protocol flow that would otherwise be implemented in hand-rolled state machines, but it's important to understand where your design may need to support separate tasks that can make progress independently and concurrently.</p>
<h2 id="final-thoughts"><a class="header" href="#final-thoughts">Final thoughts</a></h2>
<p>Studying the source code of Tokio, Mio, and futures has really helped solidify my comprehension of Tokio, and validates my strategy of clarifying abstractions through the understanding of their concrete implementations. This approach could pose a danger of only learning narrow use cases for the abstractions, so we must consciously consider the concretes as only being examples that shed light on the general cases. Reading the Tokio tutorials after studying the source code, I find myself with a bit of a hindsight bias: Tokio makes sense, and should have been easy to understand to begin with!</p>
<p>I still have a few remaining questions that I'll have to research some other day:</p>
<ul>
<li>Does Tokio deal with the starvation problem of edge triggering? I suppose it could be handled within the future by limiting the number of read/writes in a single <code>poll()</code>. When the limit is reached, the future could return early after explicitly notifying the current task instead of relying on the implicit &quot;schedule-on-<code>WouldBlock</code>&quot; behavior of the Tokio I/O source types, thus allowing other tasks and futures a chance to make progress.</li>
<li>Does Tokio support any way of running the event loop itself on multiple threads, instead of relying on finding opportunities to offload work to worker threads to maximize use of processor cores?</li>
</ul>
<p><em>UPDATE 2017-12-19: There is a <a href="https://www.reddit.com/r/rust/comments/7klghl/tokio_internals_understanding_rusts_asynchronous/">Reddit thread on r/rust</a> discussing this post. Carl Lerche, author of Mio, has posted some informative comments <a href="https://www.reddit.com/r/rust/comments/7klghl/tokio_internals_understanding_rusts_asynchronous/drfw5n1/">here</a> and <a href="https://www.reddit.com/r/rust/comments/7klghl/tokio_internals_understanding_rusts_asynchronous/drfwc1m/">here</a>. In addition to addressing the above questions, he notes that <code>FuturesUnordered</code> provides a means of combining futures such that only the relevant child futures will be polled, thus avoiding polling every future as <code>join_all()</code> would, with the tradeoff of additional allocations. Also, a future version of Tokio will be migrating away from the <code>mio::Registration</code> scheme for notifying tasks, which could streamline some of the steps described earlier.</em></p>
<p><em>UPDATE 2017-12-21: It looks like Hacker News also had a <a href="https://news.ycombinator.com/item?id=15972593">discussion of this post</a>.</em></p>
<p><em>UPDATE 2018-01-26: I created a <a href="https://github.com/simmons/tokio-aio-examples">GitHub repository</a> for my Tokio example code.</em></p>
<p>posted at 2017-12-18 06:35:38 US/Mountain by <a href="https://davidsimmons.com/">David Simmons</a></p>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                            <a rel="prev" href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>

                            <a rel="next" href="../../09_源码分析/Tokio_internals/译文：Tokio內部机制.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                    <a rel="prev" href="../../09_源码分析/tokio.rs_runtime的实现/tokio.rs_runtime的实现.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>

                    <a rel="next" href="../../09_源码分析/Tokio_internals/译文：Tokio內部机制.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
            </nav>

        </div>




        <script type="text/javascript">
            window.playground_copyable = true;
        </script>


        <script src="../../elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../searcher.js" type="text/javascript" charset="utf-8"></script>

        <script src="../../clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="../../book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->


    </body>
</html>
